﻿/******************************************************************************
 * This file is part of libemb.
 *
 * libemb is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * libemb is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with libemb.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Project: Embedme
 * Author : FergusZeng
 * Email  : cblock@126.com
 * git	  : https://git.oschina.net/cblock/embedme
 * Copyright 2014~2017 @ ShenZhen ,China
*******************************************************************************/
#ifdef OS_CYGWIN
#else
#include "curl/curl.h"
#include "HttpClient.h"
#include "Tracer.h"
#include <stdlib.h>
#include <string.h>


#define URL_MAX_LEN 2083
namespace libemb{
typedef enum
{
    HTTPREQ_GET=0,
    HTTPREQ_POST
}HTTTPREQ_E;

typedef enum{
    DOWNLOAD_STATE_STOP=0,
    DOWNLOAD_STATE_START,
    DOWNLOAD_STATE_PAUSE,
    DOWNLOAD_STATE_FINISHED,
}DOWNLOAD_STATE_E;

/**
 *  \class  FileDownLoad_S
 *  \brief  文件下载结构体 
 */
typedef struct{
    char m_url[URL_MAX_LEN+1];
    FILE* m_fp;
    int m_state;
}FileDownLoad_S;

HttpClient::HttpClient()
{
    curl_global_init(CURL_GLOBAL_ALL);
}

HttpClient::~HttpClient()
{
    curl_global_cleanup();
}

void HttpClient::run()
{
    while(1)
    {
    }
}

/**
 *  \brief  发送GET请求
 *  \param  url 目标URL
 *  \param  cacheFile 缓存文件(必须具有可写属性),用于接收服务器回应数据
 *  \return 成功返回STATUS_OK,失败返回STATUS_ERROR.
 *  \note   none
 */
int HttpClient::httpGet(const std::string url,File* cacheFile,int timeoutSeconds)
{    
    AutoLock lock(&m_reqLock);
    if (url.size()>URL_MAX_LEN || 
        url.empty())
    {
        TRACE_ERR_CLASS("Invalid URL size=%d.\n",url.size());
        return STATUS_ERROR;
    }
    if (cacheFile==NULL)
    {
        return STATUS_ERROR;
    }
    if (timeoutSeconds<0)
    {
        timeoutSeconds = 20;
    }

    CURL* curl = curl_easy_init();  
    if (curl) 
    {   
        int ret=STATUS_OK;
        /* 设置URL */
        curl_easy_setopt(curl, CURLOPT_URL, url.c_str());

        /* 设置返回的数据写入到指定文件 */
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, cacheFile->getFp());

        /* 设置请求超时时间 */
        curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeoutSeconds);

        CURLcode res = curl_easy_perform(curl); 
        if(res != CURLE_OK)      
        {
            ret = STATUS_ERROR;
            TRACE_ERR_CLASS("curl perform failed:%s\n",curl_easy_strerror(res));
        }
        curl_easy_cleanup(curl);
        return ret;
    }
    else
    {
        TRACE_ERR_CLASS("curl init failed!\n");
        return STATUS_ERROR;
    }
}

/**
 *  \brief  发送POST请求
 *  \param  url 目标URL
 *  \param  postString post字符串
 *  \param  cacheFile 缓存文件(必须具有可写属性),用于接收服务器回应数据
 *  \return 成功返回STATUS_OK,失败返回STATUS_ERROR.
 *  \note   none
 */
int HttpClient::httpPost(const std::string url,const std::string postString,File* cacheFile,int timeoutSeconds)
{
    AutoLock lock(&m_reqLock);
    if (url.size()>URL_MAX_LEN || 
        url.empty())
    {
        TRACE_ERR_CLASS("Invalid URL size=%d.\n",url.size());
        return STATUS_ERROR;
    }
    if (cacheFile==NULL)
    {
        return STATUS_ERROR;
    }
    if (timeoutSeconds<0)
    {
        timeoutSeconds = 20;
    }
    
    CURL* curl = curl_easy_init();  
    if (curl) 
    {   
        int ret=STATUS_OK;
        /* 设置URL */
        curl_easy_setopt(curl, CURLOPT_URL, url.c_str());

        /* 设置返回的数据写入到指定文件 */
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, cacheFile->getFp());

        /* 设置请求超时时间 */
        curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeoutSeconds);

        /* post数据 */
        curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postString.c_str());

        CURLcode res = curl_easy_perform(curl); 
        if(res != CURLE_OK)      
        {
            ret = STATUS_ERROR;
            TRACE_ERR_CLASS("curl perform failed:%s\n",curl_easy_strerror(res));
        }
        curl_easy_cleanup(curl);
        return ret;
    }
    else
    {
        TRACE_ERR_CLASS("curl init failed!\n");
        return STATUS_ERROR;
    }
}

/**
 *  \brief  文件下载请求
 *  \param  url 目标文件URL
 *  \param  cacheFile 缓存文件(必须具有可写属性),用于接收服务器回应数据
 *  \return 成功返回STATUS_OK,失败返回STATUS_ERROR.
 *  \note   none
 */
int HttpClient::httpFileDownLoad(const std::string url,File* cacheFile)
{
    AutoLock lock(&m_reqLock);
    if (url.size()>URL_MAX_LEN || 
        url.empty())
    {
        TRACE_ERR_CLASS("Invalid URL size=%d.\n",url.size());
        return STATUS_ERROR;
    }
    
    if (NULL==cacheFile)
    {
        TRACE_ERR_CLASS("Invalid param: fp=NULL.\n");
        return STATUS_ERROR;
    }
    FileDownLoad_S* taskArg = (FileDownLoad_S*)malloc(sizeof(FileDownLoad_S));
    if (NULL==taskArg)
    {
        TRACE_ERR_CLASS("http request malloc failed.\n");
        return STATUS_ERROR;    
    }
    memset(taskArg,0,sizeof(FileDownLoad_S));
    memcpy(taskArg->m_url,url.c_str(),url.size());
    taskArg->m_fp = cacheFile->getFp();
    m_mainThread.createTask(this, task_selector(HttpClient::fileDownLoadTask), taskArg);
    return STATUS_OK;
}

/* 文件下载线程 */
void HttpClient::fileDownLoadTask(void* arg)
{
    AutoLock lock(&m_reqLock);
    FileDownLoad_S* taskArg = (FileDownLoad_S*)arg;
    
    //not implement
    TRACE_YELLOW("download task start: %s\n",taskArg->m_url);

    CURL* curl = curl_easy_init();  
    if (curl) 
    {   
        /* 设置URL */
        curl_easy_setopt(curl, CURLOPT_URL, taskArg->m_url);

        /* 设置文件写入回调函数 */
        //curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeData);
        
        /* 设置返回的数据写入到指定文件 */
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, taskArg->m_fp);

        /* 设置重定向的最大次数 */
        curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 5);

        /* 开始下载 */
        CURLcode res = curl_easy_perform(curl); 
        if(res != CURLE_OK)      
        {
            TRACE_ERR_CLASS("curl perform failed:%s\n",curl_easy_strerror(res));
        }
        curl_easy_cleanup(curl);
    }

    TRACE_YELLOW("download task exit.\n");
    free(taskArg);
}
}
#endif